use std::sync::Arc;

use axum::{extract::{Path, Query}, routing::{get, post, put}, Extension, Json, Router};

use crate::{
    error::{HttpError, R},
    model::{CreateTodo, EditTodo, QueryTodo, Todo},
    service::{get_todos_by_active, save_todo, update_todo},
    AppState,
};

pub fn todo_router() -> Router {
    let router = Router::new()
        .route("/", post(create_todo))
        .route("/", get(get_todos))
        .route("/{todo_id}", put(complete_todo));

    Router::new().nest("/todos", router)
}

async fn create_todo(
    Extension(app_state): Extension<Arc<AppState>>,
    Json(body): Json<CreateTodo>,
) -> R<Todo> {
    let title = body.title;

    let todo = save_todo(&app_state.pool, &title)
        .await
        .map_err(|e| HttpError::server_error(e.to_string()))?;

    Ok(Json(todo))
}

async fn get_todos(
    Extension(app_state): Extension<Arc<AppState>>,
    Query(body): Query<QueryTodo>,
) -> R<Vec<Todo>> {
    let todos = get_todos_by_active(&app_state.pool, body.active)
        .await
        .map_err(|e| HttpError::server_error(e.to_string()))?;

    Ok(Json(todos))
}

async fn complete_todo(
    Extension(app_state): Extension<Arc<AppState>>,
    Path(todo_id): Path<i64>,
    Json(body): Json<EditTodo>,
) -> R<Todo> {
    let todo = update_todo(&app_state.pool, todo_id, body.active)
        .await
        .map_err(|e| HttpError::server_error(e.to_string()))?;

    Ok(Json(todo))
}
